package com.emeraldparser.grammar;

import static com.emeraldparser.symbol.SymbolClasses.*;

public class Grammars {

	public static Grammar buildGrammarGrammar() {
		Grammar.Builder builder = Grammar.builder();
		
		builder.addTokenRule( Rule.create( named("identifier"), oneOrMore(any(range('a', 'z'), literal("_"))) ) );
		
		builder.addTokenRule( Rule.create( named("literal"), concat(literal("\""), range('0', '9'), literal("\"")) ) );
		
		builder.addProductionRule( Rule.create( concat(), any(literal(' '), literal('\n'), literal("\r\n"), literal("\t")) ) );
		
		Rule startRule = Rule.create( named("start"), concat(startOfInput(), named("grammar"), endOfInput()) );
		builder.addProductionRule(startRule);
		builder.setStartRule(startRule);
		
		builder.addProductionRule(
					Rule.create(
						named("grammar"),
						concat(
								optional(named("token_section")),
								optional(named("production_section"))
							)
					)
			);
		
		builder.addProductionRule(
				Rule.create(
						named("token_section"),
						concat(literal("Tokens"), repeated(named("rule")))
					)
			);
		
		builder.addProductionRule(
				Rule.create(
						named("production_section"),
						concat(literal("Productions"), repeated(named("rule")))
					)
			);
		
		builder.addProductionRule(
				Rule.create(
						named("rule"),
						concat(
								named("expression"),
								literal("="),
								named("expression")
							)
					)
			);
		
		builder.addProductionRule(
				Rule.create(
						named("expression"),
						any
						(
							// Named:
							named("identifier"),
							
							// Concatenation:
							concat(literal("("), repeated(named("expression")), literal(")")),
							
							// Alternation:
							concat(literal("("), named("expression"), oneOrMore(concat(literal("|"), named("expression"))), literal(")")),
							
							// Optional:
							concat(named("expression"), literal("?")),
							
							// Zero or more:
							concat(named("expression"), literal("*")),
							
							// One or more:
							concat(named("expression"), literal("+")),
							
							// Range:
							concat(literal("("), named("literal"), literal(".."), named("literal"), literal(")"))
						)
					)
			);
		
		return builder.build();
	}

}
